/*
 * =====================================================================================
 *
 *       Filename:  openvpn_pre.c
 *
 *    Description:  do necessary thing before openvpn
 *                  1. timesync
 *                  2. generate user and passwd
 *                  3. generate openvpn configure(openwrt可以省略)
 *                  4. 开启openvpn
 *                  5. 地址映射，arpproxy等必要的事情(工作量不少啊)
 *
 *        Version:  1.0
 *        Created:  2018年11月16日 13时46分04秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (), 
 *   Organization:  
 *
 * =====================================================================================
 */


#include <time.h>
#include <fcntl.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
/* ulibc: __USE_GUN
 * glibs: _GUN_SOURCE
 */
#define __USE_GNU
#include <string.h>
#include <syslog.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>  
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdarg.h>

#include <sys/ioctl.h>
#include <net/if.h>
#include <openssl/md5.h>

#include <syslog.h>
#include <signal.h>
#include <stdarg.h>

typedef void(*sighandler_t)(int);
int SYSTEM(const char *format, ...)
{
    va_list arg;
    char buf[4096]= {0};

    memset(buf, 0, sizeof(buf));
    va_start(arg, format);
    vsnprintf(buf,4096, format, arg);
    va_end(arg);

    sighandler_t old_handler = signal(SIGCHLD, SIG_DFL);
    int ret = system(buf);
    if(ret == -1) {
        syslog(LOG_INFO, "no launch: %s", buf);
    }
    else if(WIFEXITED(ret)) {
        syslog(LOG_INFO, "normal exitcode-%d: %s", WEXITSTATUS(ret), buf);
    }
    else if(WIFSIGNALED(ret)) {
        syslog(LOG_INFO, "signal-%d: %s", WTERMSIG(ret));
    }
    else {
        syslog(LOG_INFO, "*abnormal exit %d: %s", ret, buf);
    }
    signal(SIGCHLD, old_handler);
    usleep(1000);
    return ret;
}


#ifdef OPENVPN_REMAP_MODE_SEL_SUPPORT
int convacs_get_remap_mode(char *mode)
{
    char *convacs_mode= nvram_safe_get("convacs_mode");
    if (convacs_mode && convacs_mode[0]) {
        strcpy(mode, convacs_mode);
    }
    else {
        strcpy(mode, "wan");
    }
    free(convacs_mode);
    return 0;
}
#endif

int get_mac(char *name, unsigned char *mac, int len)
{
    int fd;   
    struct ifreq ifr;   
    struct sockaddr sa;   
    struct sockaddr_in sin;   

    fd = socket(AF_INET, SOCK_DGRAM, 0);   
    if(fd < 0) {
        perror("socket()");
        return -1;
    }
    strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
    ifr.ifr_name[IFNAMSIZ-1] = 0;

    //memset(mac,0,sizeof(mac));   
    if(ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
        close(fd);
        perror("ioctl()");
        return -2;
    }

    memcpy(&sa,&ifr.ifr_addr,sizeof(sin));
    memcpy(mac, sa.sa_data, len);

    close(fd);
    return 0;
}


/*
 * 作用: 用户名是mac地址字符串
 *       算出密码(插入magic word， 计算MD5, 取出前八位作为密码)
 * return: ok:0, failed:-1
 */
int openvpn_calc_mac_password(char *mac, char *psw)
{
    if(NULL == mac) {
        return -1;
    }

    size_t idx = 0;
    unsigned char buff[100] = {0};
    uint32_t md5[4];
    buff[idx++] = mac[0];
    buff[idx++] = mac[1];
    buff[idx++] = 'h';

    buff[idx++] = mac[2];
    buff[idx++] = mac[3];
    buff[idx++] = 'e';

    buff[idx++] = mac[4];
    buff[idx++] = mac[5];
    buff[idx++] = 'n';

    buff[idx++] = mac[6];
    buff[idx++] = mac[7];
    buff[idx++] = 'g';

    buff[idx++] = mac[8];
    buff[idx++] = mac[9];
    buff[idx++] = 's';

    buff[idx++] = mac[10];
    buff[idx++] = mac[11];

    //md5sum_string(buff, idx, md5);
    MD5((const unsigned char *)buff, idx, (unsigned char *)md5);
    sprintf(psw, "%08x", md5[0]);

    return 0;
}

/*
 * 用户名用WAN口地址的MAC
 */
int set_username_passwd(const char *username, const char *password)
{
    int fd = open("./config/password.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);
    if(fd < 0) {
        perror("open(./config/password.txt)");
        return -1;
    }

    write(fd, username, strlen(username));
    write(fd, "\n", 1);
    write(fd, password, strlen(password));
    printf("username=%s, password: %s\n", username, password);
    close(fd);
    return 0;
}

void shutdown_convacs()
{
    SYSTEM("killall -9 timesync");
    SYSTEM("killall -9 convacs_route");
    SYSTEM("/etc/init.d/openvpn stop");
    sleep(1);
}

int main(int argc, char **argv)
{
    if(argc != 5) {
        printf("%s ip port username password\n", argv[0]);
        return 0;
    }
    shutdown_convacs();
    SYSTEM("mkdir -pv /tmp/openvpn && rm -rf /tmp/openvpn/*");
    char *server_ip = argv[1];
    unsigned short server_port = atoi(argv[2]);
    char *username = argv[3];
    char *password = argv[3];
    /* 1. timesync */
    SYSTEM("./timesync -c %s -p 49000 >/dev/null 2>&1 &", server_ip);

    /* 2. user and password */
    if(set_username_passwd(username, password) < 0) {
        printf("failed to set_username_passwd\n");
        return 0;
    }
    printf("2\n");

    /* 3. 设置openvpn配置文件 */
    SYSTEM("cp ./config/client_sample.conf ./config/client.conf");
    /* echo "remote \"192.168.10.11 1194\"" */
    SYSTEM("echo 'remote \"%s %d\"' >> ./config/client.conf", server_ip);
    SYSTEM("echo 'port %u' >> ./config/client.conf", server_port);

    SYSTEM("cp -rf ./config /tmp/openvpn");
    /* 4. 开启openvpn */
    //如何开启opevpn呢?
    SYSTEM("openvpn --config /tmp/openvpn/config/client.conf");
    /* 5. 地址映射及其他 */
    /* 在openvpn的up和down命令中开启/关闭remap, arpproxy等 */
    return 0;
}


